﻿using Microsoft.AspNetCore.SignalR;
using PmSoft.Core;
using System.Security.Claims;
using PmSoft.Core.Domain.Auth;

namespace PmSoft.Web.Abstractions.SignalR;

/// <summary>
/// 为 <see cref="HubCallerContext"/> 提供扩展方法，用于从 SignalR 调用上下文中提取用户信息。
/// </summary>
public static class HubCallerContextExtensions
{
	/// <summary>
	/// 从调用上下文中获取租户类型。
	/// </summary>
	/// <param name="context">SignalR 调用上下文。</param>
	/// <returns>租户类型，如果不存在或无法解析则返回 null。</returns>
	public static string? GetTenantType(this HubCallerContext context)
	{
		if (context?.User == null)
		{
			return null;
		}

		var tenantIdClaim = context.User.Claims.FirstOrDefault(c => c.Type == "TenantType");
		if (string.IsNullOrEmpty(tenantIdClaim?.Value))
		{
			return null;
		}

		return tenantIdClaim.Value;
	}

	/// <summary>
	/// 从调用上下文中获取用户 ID，如果不存在则返回 null。
	/// </summary>
	/// <param name="context">SignalR 调用上下文。</param>
	/// <returns>用户 ID，如果不存在或无法解析则返回 null。</returns>
	public static int? GetUserIdOrNull(this HubCallerContext context)
	{
		if (context?.User == null)
		{
			return null;
		}

		var userIdClaim = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
		if (string.IsNullOrEmpty(userIdClaim?.Value))
		{
			return null;
		}

		if (!int.TryParse(userIdClaim.Value, out var userId))
		{
			return null;
		}

		return userId;
	}

	/// <summary>
	/// 从调用上下文中获取用户 ID，如果不存在则抛出异常。
	/// </summary>
	/// <param name="context">SignalR 调用上下文。</param>
	/// <returns>用户 ID。</returns>
	/// <exception cref="PmSoftException">如果用户 ID 为 null（可能用户未登录），则抛出。</exception>
	public static int GetUserId(this HubCallerContext context)
	{
		var userId = context.GetUserIdOrNull();
		if (userId == null)
		{
			throw new PmSoftException("用户 ID 为 null！可能是用户未登录。");
		}

		return userId.Value;
	}
 

	/// <summary>
	/// 从调用上下文创建 <see cref="UserIdentifier"/> 对象。
	/// </summary>
	/// <param name="context">SignalR 调用上下文。</param>
	/// <returns>用户标识对象，如果用户 ID 不存在则返回 null。</returns>
	public static UserIdentifier? ToUserIdentifier(this HubCallerContext context)
	{
		var userId = context.GetUserIdOrNull();
		if (userId == null)
		{
			return null;
		}

		return new UserIdentifier(context.GetTenantType(), context.GetUserId());
	}
}